#include <dim-sum/types.h>
#include <dim-sum/uaccess.h>
#include <dim-sum/bug.h>
#include <dim-sum/err.h>
#include <dim-sum/errno.h>
#include <dim-sum/process.h>
#include <dim-sum/mm_types.h>
#include <dim-sum/beehive.h>
#include <dim-sum/exec.h>
#include <dim-sum/sched.h>
#include <dim-sum/fs.h>
#include <dim-sum/fcntl.h>
#include <dim-sum/auxvec.h>
#include <dim-sum/elf.h>
#include <dim-sum/mmu.h>
#include <dim-sum/syscall.h>
#include <dim-sum/random.h>
#include <asm/asm-offsets.h>
#include <asm/exception.h>
#include <dim-sum/file.h>

/**
 * 分配新的exec_info结构体
 */
static struct exec_info* alloced_exec_info(void)
{
	return (struct exec_info*)
		kzalloc(sizeof(struct exec_info), PAF_KERNEL);
}

static void exec_info_clean(struct exec_info* info)
{
	struct arg_env_info* ae_info;
	int i = 0;

	ae_info = &info->ae_info;

	if (ae_info->filename) {
		/**
		 * 为什么不用kfree，可以参照vmem_file_preparse函数
		 * 中使用clone_user_string函数获取用户态空间的文件名
		 */
		discard_user_string(ae_info->filename);
		ae_info->filename = NULL;
		ae_info->filename_sz = 0;
	}
	if (ae_info->script_name) {
		kfree(ae_info->script_name);
		ae_info->script_name = NULL;
		ae_info->script_name_sz = 0;
	}
	if (ae_info->script_arg) {
		kfree(ae_info->script_arg);
		ae_info->script_arg = NULL;
		ae_info->script_arg_sz = 0;
	}

	if (ae_info->k_argv_spot) {
		while (i < ae_info->k_argv_spot_max) {
			if (ae_info->k_argv_spot[i]) {
				kfree(ae_info->k_argv_spot[i]);
				ae_info->k_argv_spot[i] = NULL;
			}
			i++;
		}
	}

	i = 0;
	if (ae_info->k_envp_spot) {
		while (i < ae_info->k_envp_spot_max) {
			if (ae_info->k_envp_spot[i]) {
				kfree(ae_info->k_envp_spot[i]);
				ae_info->k_envp_spot[i] = NULL;
			}
			i++;
		}
	}
	
	if (ae_info->k_rand_arr) {
		kfree(ae_info->k_rand_arr);
		ae_info->k_rand_arr = NULL;
		ae_info->k_rand_arr_sz = 0;
	}

	if (ae_info->k_auxv_arr) {
		kfree(ae_info->k_auxv_arr);
		ae_info->k_auxv_arr = NULL;
		ae_info->k_auxv_arr_sz = 0;
	}

	if (ae_info->k_envp_spot) {
		kfree(info->ae_info.k_envp_spot);
		ae_info->k_envp_spot = NULL;
	}
	if (ae_info->k_argv_spot) {
		kfree(info->ae_info.k_argv_spot);
		ae_info->k_argv_spot = NULL;
	}
	return;
}

/**
 * 释放exec_info结构体
 */
static void free_exec_info(struct exec_info* info)
{
	BUG_ON(!info);

	exec_info_clean(info);

	if (info->elf_hdr)
		kfree((void*)info->elf_hdr);
	if (info->exe_phdr)
		kfree((void*)info->exe_phdr);

	kfree((void*)info);
	return;
}

/**
 * 该函数仅在task_argenv_user函数中使用，其它地方不能使用
 */
static inline void argenvaux_to_user(void __user *to, const void *from, unsigned long n)
{
	BUG_ON(!to || !from);
	/**
	 * 因为在copy_to_user中会打开访问用户内存的机制，所以这里先要关闭
	 */
	disable_usermem_access();
	copy_to_user(to, from, n);
	enable_usermem_access();
	return;
}

/**
 * 该函数仅在task_argenv_kernel函数中使用，其它地方不能使用
 */
static inline unsigned long argenvaux_from_user(void *to, const void *from, unsigned long n)
{
	unsigned long ret = 0;
	BUG_ON(!to || !from);
	/**
	 * 因为在copy_from_user中会打开访问用户内存的机制，所以这里先要关闭
	 */
	disable_usermem_access();
	ret = copy_from_user(to, from, n);
	enable_usermem_access();
	return ret;
}

/**
 * 统计argv或者envp计数
 */
static long arg_env_nr(char * const *p)
{
	unsigned long i = 0;
	if (!p)
		return 0;
	while (p[i] != NULL) {
		i++;
		if (i > ARG_STRINGS_MAX)
			return 0;
	}
	return i;
}

/**
 * 基于arg_env_info中分配argv和envp
 * 在用户地址空间中占用的内存
 */
static void* ae_info_ualloc(struct arg_env_info* info, size_t size)
{
	void* ret;
	if (!info || !size)
		return NULL;
	if (!info->unext || info->unext < info->ustart ||
		(void*)((unsigned long)(info->unext) + size) > info->utop)
		return NULL;
	ret = info->unext;
	info->unext = (void*)((unsigned long)(info->unext) + size);
	return ret;
}

/**
 * 获取argv envp参数在用户栈中的开始地址
 */
static int argv_envp_init(struct exec_info* info)
{
	long argvi, envi;
	int ret = -EFAULT;
	
	argvi = arg_env_nr(info->ae_info.app_argv);
	envi = arg_env_nr(info->ae_info.app_envp);
	
	info->ae_info.k_argv_spot_max = argvi;
	info->ae_info.k_envp_spot_max = envi;
	info->ae_info.k_auxv_arr_sz = sizeof(struct elf_auxv) * (AUXV_NR);
	info->ae_info.k_rand_arr_sz = RAND_CHAR_SIZE;

	if (info->ae_info.script_name)
		info->ae_info.k_argv_spot_max++;
	if (info->ae_info.script_arg)
		info->ae_info.k_argv_spot_max++;
	
	info->ae_info.k_argv_spot_max++;
	info->ae_info.k_envp_spot_max++;
	
	
	info->ae_info.k_argv_spot = kzalloc(sizeof(char*) * info->ae_info.k_argv_spot_max, PAF_KERNEL);
	if (!info->ae_info.k_argv_spot) {
		return -ENOMEM;
	}

	info->ae_info.k_envp_spot = kzalloc(sizeof(char*) * info->ae_info.k_envp_spot_max, PAF_KERNEL);
	if (!info->ae_info.k_envp_spot) {
		ret = -ENOMEM;
		goto out;
	}

	info->ae_info.k_auxv_arr = kzalloc(info->ae_info.k_auxv_arr_sz, PAF_KERNEL);
	if (!info->ae_info.k_auxv_arr) {
		ret = -ENOMEM;
		goto out;
	}

	info->ae_info.k_rand_arr = kzalloc(info->ae_info.k_rand_arr_sz, PAF_KERNEL);
	if (!info->ae_info.k_rand_arr) {
		ret = -ENOMEM;
		goto out;
	}

	return 0;

out:
	if (info->ae_info.k_rand_arr) {
		kfree(info->ae_info.k_rand_arr);
	}
	if (info->ae_info.k_auxv_arr) {
		kfree(info->ae_info.k_auxv_arr);
	}
	if (info->ae_info.k_envp_spot) {
		kfree(info->ae_info.k_envp_spot);
	}
	if (info->ae_info.k_argv_spot) {
		kfree(info->ae_info.k_argv_spot);
	}
	
	return ret;
}

static int ae_kernel_argvspot_insert(struct exec_info* info, char* argv, long spot, int from)
{
	char* kstrmem = NULL;
	size_t len = 0;
	
	if (!info || !argv)
		return -EINVAL;
	if (!info->ae_info.k_argv_spot)
		return -EINVAL;
	
	if (spot < 0 || spot >= info->ae_info.k_argv_spot_max)
		return -EINVAL;
	
	
	len = strlen(argv);
	if (len < 1) 
		return -EINVAL;

	kstrmem = (char*)kzalloc(len + 1, PAF_KERNEL);
	if (!kstrmem)
		return -ENOMEM;
	if (from) {
		if (!strcpy(kstrmem, argv)) {
			kfree(kstrmem);
			return -EFAULT;
		}
	} else {
		if (argenvaux_from_user(kstrmem, argv, len)) {
			kfree(kstrmem);
			return -EFAULT;
		}
	}
	
	if (info->ae_info.k_argv_spot[spot])
		kfree(info->ae_info.k_argv_spot[spot]);

	info->ae_info.k_argv_spot[spot] = kstrmem;
	return 0;
}

static int ae_kernel_envspot_insert(struct exec_info* info, char* env, long spot, int from)
{
	char* kstrmem = NULL;
	size_t len = 0;
	if (!info || !env)
		return -EINVAL;

	if (!info->ae_info.k_envp_spot)
		return -EINVAL;

	if (spot < 0 || spot >= info->ae_info.k_envp_spot_max)
		return -EINVAL;
	
	len = strlen(env);
	if (len < 1)
		return -EINVAL;

	kstrmem = (char*)kzalloc(len + 1, PAF_KERNEL);
	if (!kstrmem)
		return -ENOMEM;

	if (from) {
		if (!strcpy(kstrmem, env)) {
			kfree(kstrmem);
			return -EFAULT;
		}
	} else {
		if (argenvaux_from_user(kstrmem, env, len)) {
			kfree(kstrmem);
			return -EFAULT;
		}
	}
	
	if (info->ae_info.k_envp_spot[spot])
		kfree(info->ae_info.k_envp_spot[spot]);

	info->ae_info.k_envp_spot[spot] = kstrmem;
	return 0;
}

static int ae_kernel_auvx_randchar(struct exec_info* info)
{
	char* krand_p = NULL;
	struct elf_auxv* kauxv;
	int i = 0;
	if (!info)
		return -EINVAL;

	kauxv = info->ae_info.k_auxv_arr;
	krand_p = info->ae_info.k_rand_arr;
	if (!kauxv)
		return -EINVAL;

	if (krand_p)
		get_random_bytes(krand_p, RAND_CHAR_SIZE);
	BUG_ON(!info->entry || !info->load_addr);
	NEW_AUX_ENT(&kauxv[i+0], AT_PAGESZ, ELF_EXEC_PAGESIZE);
	NEW_AUX_ENT(&kauxv[i+1], AT_CLKTCK, 100);
	NEW_AUX_ENT(&kauxv[i+2], AT_PHDR, info->load_addr + info->elf_hdr->e_phoff);
	NEW_AUX_ENT(&kauxv[i+3], AT_PHENT, sizeof(struct elf_phdr));
	NEW_AUX_ENT(&kauxv[i+4], AT_PHNUM, info->elf_hdr->e_phnum);
	NEW_AUX_ENT(&kauxv[i+5], AT_BASE, info->interp_load_addr);
	NEW_AUX_ENT(&kauxv[i+6], AT_FLAGS, 0);
	NEW_AUX_ENT(&kauxv[i+7], AT_ENTRY, info->entry);
	NEW_AUX_ENT(&kauxv[i+8], AT_RANDOM, (elf_addr_t)(unsigned long)krand_p);
	NEW_AUX_ENT(&kauxv[i+9], AT_NULL, 0);
	return 0;
}

static int ae_argvenvp_size(struct exec_info* info)
{
	int i = 0;
	if (!info)
		return -EINVAL;
	
	info->ae_info.write_user_size = 0;
	info->ae_info.write_user_size += sizeof(void*);

	if (info->ae_info.k_argv_spot) {
		while (i < info->ae_info.k_argv_spot_max) {
			if (info->ae_info.k_argv_spot[i]) {
				info->ae_info.write_user_size += (strlen(info->ae_info.k_argv_spot[i]) + 1);
			} else {
				info->ae_info.write_user_size += sizeof(info->ae_info.k_argv_spot[i]);
			}
			i++;
		}
	} else {
		info->ae_info.write_user_size += sizeof(char*);
	}

	i = 0;
	if (info->ae_info.k_envp_spot) {
		while (i < info->ae_info.k_envp_spot_max) {
			if (info->ae_info.k_envp_spot[i]) {
				info->ae_info.write_user_size += (strlen(info->ae_info.k_envp_spot[i]) + 1);
			} else {
				info->ae_info.write_user_size += sizeof(info->ae_info.k_envp_spot[i]);
			}
			i++;
		}
	} else {
		info->ae_info.write_user_size += sizeof(char*);
	}

	if (info->ae_info.k_auxv_arr) {
		info->ae_info.write_user_size += info->ae_info.k_auxv_arr_sz;
	} else {
		info->ae_info.write_user_size += sizeof(char*);
	}

	if (info->ae_info.k_rand_arr) {
		info->ae_info.write_user_size += info->ae_info.k_rand_arr_sz;
	} else {
		info->ae_info.write_user_size += sizeof(char*);
	}
	return 0;
}

__maybe_unused static void dump_ae_info(struct arg_env_info* info)
{	
	int i = 0;
	if (!info)
		return;
	if (info->filename)
		pr_info("task:%s %s filename:%s\n", current->name, __func__, info->filename);
	if (info->script_name)
		pr_info("task:%s %s srcipt_name:%s\n", current->name, __func__, info->script_name);
	if (info->script_arg)
		pr_info("task:%s %s srcipt_arg:%s\n", current->name, __func__, info->script_arg);
	
	pr_info("task:%s %s info write_user_size:%ld\n", current->name, __func__, info->write_user_size);
	pr_info("task:%s %s info app_argv:%p app_envp:%p\n", current->name, __func__, info->app_argv, info->app_envp);
	pr_info("task:%s %s info info->app_argv_count:%ld info->app_envp_count:%ld\n", current->name, __func__, info->app_argv_count, info->app_envp_count);
	pr_info("task:%s %s info k_argv_spot:%p k_argv_spot_max:%ld\n", current->name, __func__, info->k_argv_spot, info->k_argv_spot_max);
	pr_info("task:%s %s info k_envp_spot:%p k_envp_spot_max:%ld\n", current->name, __func__, info->k_envp_spot, info->k_envp_spot_max);
	pr_info("task:%s %s info k_auxv_arr:%p k_auxv_arr_sz:%ld\n", current->name, __func__, info->k_auxv_arr, info->k_auxv_arr_sz);
	pr_info("task:%s %s info k_rand_arr:%p k_rand_arr_sz:%ld\n", current->name, __func__, info->k_rand_arr, info->k_rand_arr_sz);
	if (info->k_argv_spot) 
		while ((info->k_argv_spot[i])) {
			pr_info("task:%s %s cmdline:%s\n", current->name, __func__, info->k_argv_spot[i]);
			i++;
		}
	i = 0;
	if (info->k_envp_spot) 
		while ((info->k_envp_spot[i])) {
			pr_info("task:%s %s env:%s\n", current->name, __func__, info->k_envp_spot[i]);
			i++;
		}
	i = 0;
	if (info->uargv_p) 
		while ((info->uargv_p[i])) {
			pr_info("%s user_cmdline:%s %p[%d] %p\n", __func__, info->uargv_p[i], info->uargv_p, i, info->uargv_p[i]);
			i++;
		}
	i = 0;
	if (info->uenvp_p) 
		while ((info->uenvp_p[i])) {
			pr_info("%s user_env:%s %p[%d] %p\n", __func__, info->uenvp_p[i], info->uenvp_p, i, info->uenvp_p[i]);
			i++;
		}
}

/**
 * 复制命令行和环境变量到内核地址空间中
 */
static int task_argenv_kernel(struct exec_info* info, char * const *argv, char * const *envp)
{
	int ret;
	int i = 0, uai = 0;
	
	enable_usermem_access();
	
	ret = argv_envp_init(info);
	if (ret) {
		info->ae_info.ustart = NULL;
		ret = -ENOMEM;
		goto out;
	}
	
	if (info->ae_info.script_name) {
		if (ae_kernel_argvspot_insert(info, info->ae_info.script_name, i, 1)) {
			ret = -EFAULT;
			goto out;
		}
		i++;
		if (info->ae_info.script_arg) {
			if (ae_kernel_argvspot_insert(info, info->ae_info.script_arg, i, 1)) {
				ret = -EFAULT;
				goto out;
			}

			i++;
		}
	}
	
	if (info->ae_info.app_argv) {
		while (info->ae_info.app_argv[uai]) {
			if (ae_kernel_argvspot_insert(info, info->ae_info.app_argv[uai], i, 0)) {
				ret = -EFAULT;
				goto out;
			}
			uai++;
			i++;
		}
	}

	uai = 0;
	if (info->ae_info.app_envp) {
		while (info->ae_info.app_envp[uai]) {
			if (ae_kernel_envspot_insert(info, info->ae_info.app_envp[uai], uai, 0)) {
				ret = -EFAULT;
				goto out;
			}
			uai++;
		}
	}

	if (ae_kernel_auvx_randchar(info)) {
		ret = -EFAULT;
		goto out;
	}
	
	info->ae_info.app_argv_count = i;
	info->ae_info.app_envp_count = uai;
	ae_argvenvp_size(info);
	ret = 0;

out:
	disable_usermem_access();
	return ret;
}

/**
 * 复制命令行和环境变量到用户地址空间中
 */
static int task_argenv_user(struct exec_info* info)
{
	size_t argcsz, argvsz, envpsz, auxvsz;

	char **uargv_p;
	char **uenvp_p;
	int* uargc_p;
	struct elf_auxv* uauxv_p;
	virt_addr_t s_top;
	size_t strsz;
	void* p;
	int i = 0;

	if (!info)
		return -EINVAL;

	if (info->ae_info.write_user_size >= (USER_STACK_SIZE - (PAGE_SIZE * 4)))
		return -EFAULT;

	s_top = mem_stack_top(current_mem);
	if (!s_top) {
		return -EFAULT;
	}

	s_top &= ~0xfUL;
	info->ae_info.utop = (void*)s_top;
	
	s_top -= (virt_addr_t)info->ae_info.write_user_size;
	s_top &= PAGE_MASK;
	info->ae_info.ustart = (void*)s_top;
	info->ae_info.unext = info->ae_info.ustart;

	argcsz = sizeof(uargc_p);
	argvsz = sizeof(*uargv_p) * (info->ae_info.k_argv_spot_max);
	envpsz = sizeof(*uenvp_p) * (info->ae_info.k_envp_spot_max);
	auxvsz = info->ae_info.k_auxv_arr_sz;

	uargc_p = (int*)ae_info_ualloc(&info->ae_info, argcsz);
	uargv_p = (char**)ae_info_ualloc(&info->ae_info, argvsz);
	uenvp_p = (char**)ae_info_ualloc(&info->ae_info, envpsz);
	uauxv_p = (struct elf_auxv*)ae_info_ualloc(&info->ae_info, auxvsz);

	/**
	 * 映射要写入栈中数据的地址区间
	 */
	BUG_ON(vmem_map_range_uaddr((virt_addr_t)info->ae_info.ustart, 
			(virt_size_t)info->ae_info.write_user_size, PROT_READ | PROT_WRITE));

	/**
	 * 有很多CPU不允许内核态代码访问用户态页面，需要打开访问用户内存的机制
	 */
	enable_usermem_access();
	memset((void*)(info->ae_info.ustart), 0, PAGE_SIZE);

	if (uargv_p) {
		if (info->ae_info.k_argv_spot)
			argenvaux_to_user(uargv_p, info->ae_info.k_argv_spot, argvsz);
		else
			*uargv_p = NULL;
	}

	if (uenvp_p) {
		if (info->ae_info.k_envp_spot)
			argenvaux_to_user(uenvp_p, info->ae_info.k_envp_spot, envpsz);
		else
			*uenvp_p = NULL;
	}

	if (uargv_p)
		while (uargv_p[i] != NULL) {
			strsz = strlen(uargv_p[i]) + 1;
			p = ae_info_ualloc(&info->ae_info, strsz);
			if (p) {
				argenvaux_to_user(p, uargv_p[i], strsz);
				uargv_p[i] = (char*)p;
			}
			i++;
		}

	if (uargc_p)
		*uargc_p = i;
	
	i = 0;
	if (uenvp_p)
		while (uenvp_p[i] != NULL) {
			strsz = strlen(uenvp_p[i]) + 1;
			p = ae_info_ualloc(&info->ae_info, strsz);
			if (p) {
				argenvaux_to_user(p, uenvp_p[i], strsz);
				uenvp_p[i] = (char*)p;
			}
			i++;
		}
	

	if (uauxv_p) {
		if (info->ae_info.k_auxv_arr) {
			argenvaux_to_user(uauxv_p, info->ae_info.k_auxv_arr, auxvsz);
			if (info->ae_info.k_rand_arr) {
				p = ae_info_ualloc(&info->ae_info, RAND_CHAR_SIZE);
				/**
				 * 分配用户态随机字符的内存
				 */
				if (p) {
					/**
					 * 复制随机字符到用户态
					 */
					argenvaux_to_user(p, (info->ae_info.k_rand_arr), RAND_CHAR_SIZE);
					/**
					 * 设置用户态随机字符的地址
					 */
					i = 0;
					while (uauxv_p[i].a_type != AT_NULL) {
						if (uauxv_p[i].a_type == AT_RANDOM)
							uauxv_p[i].a_un.a_val = (unsigned long)p;
						i++;
					}
				}
			}
		} else {
			uauxv_p[0].a_type = AT_NULL;
			uauxv_p[0].a_un.a_val = 0;
		}
	}

	info->ae_info.uargv_p = uargv_p;
	info->ae_info.uenvp_p = uenvp_p;
	disable_usermem_access();
	return 0;
}

/**
 * 建立用户信号相关的页面
 */
static int task_user_signal(void)
{
	return 0;
}

/**
 * 打开标准输入输出
 */

static int execve_open_stdio(void)
{
	// int stdinfd, stdoutfd, stderrfd;

	// stdinfd = sys_open("/dev/console", O_RDWR, 0);
	// if(stdinfd < 0) {
		
	// 	return -EBADFD;
	// }
		

	// stdoutfd = sys_dup(stdinfd);
	// if(stdoutfd < 0) {
	// 	sys_close(stdinfd);
		
	// 	return -EBADFD;
	// }

	// stderrfd = sys_dup(stdinfd);
	// if(stderrfd < 0) {
	// 	sys_close(stdinfd);
	// 	sys_close(stdoutfd);
		
	// 	return -EBADFD;
	// }
	// // current->sig->tty = current->files->fd_array[0]->private_data;
	// BUG_ON(stdinfd != 0);
	// BUG_ON(stdoutfd != 1);
	// BUG_ON(stderrfd != 2);
	return 0;
}

/**
 * 关闭标准输入输出
 */
static int execve_close_stdio(void)
{
	// int stdinfd = 0, stdoutfd = 1, stderrfd = 2;
	
	// sys_close(stdinfd);
	// sys_close(stdoutfd);
	// sys_close(stderrfd);
	return 0;
}

static void* vmem_load_file_head(int fd)
{
	int rdsz = -1;
	loff_t pos;
	void* ret;
	int err; 

	if(fd < 0)
		return NULL;

	
	ret = kzalloc(BINPRM_BUF_SIZE, PAF_KERNEL);
	if(!ret)
		return NULL;

	err = sys_llseek(fd, 0,
		 (unsigned long)0, &pos, SEEK_SET);
	if(err) {
		kfree(ret);
		return NULL;
	}

	rdsz = sys_read(fd, ret, BINPRM_BUF_SIZE);
	if (rdsz <= 0 || rdsz > BINPRM_BUF_SIZE) {
		kfree(ret);
		ret = NULL;
	}
	return ret;
}

static int script_file_preparse(struct exec_info* info, int fd)
{
	char *cp, *i_name, *i_arg, *buf;
	char *outappname = NULL, *outargname = NULL;
	long outappname_sz = 0, outargname_sz = 0;

	int exefd = fd;
	int ret = -EFAULT;
	
	buf = vmem_load_file_head(exefd);
	if (!buf) {
		return -ENOMEM;
	}
	
	if ((buf[0] != '#') || (buf[1] != '!')) {
		if (buf)
			kfree(buf);
		return 0;
	}

	buf[BINPRM_BUF_SIZE - 1] = '\0';
	if ((cp = strchr(buf, '\n')) == NULL)
		cp = buf+BINPRM_BUF_SIZE-1;
	
	*cp = '\0';
	while (cp > buf) {
		cp--;
		if ((*cp == ' ') || (*cp == '\t'))
			*cp = '\0';
		else
			break;
	}

	for (cp = buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
	if (*cp == '\0') {
		ret = -ENOEXEC; /* No interpreter name found */
		goto out;
	}

	i_name = cp;
	i_arg = NULL;
	for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
		/* nothing */ ;
	
	while ((*cp == ' ') || (*cp == '\t'))
		*cp++ = '\0';
	if (*cp)
		i_arg = cp;

	outappname_sz = (long)(strlen(i_name) + 1);
	outappname = kzalloc(outappname_sz, PAF_KERNEL);
	if (!outappname) {
		ret = -ENOMEM;
		goto out;
	}
	strcpy(outappname, i_name);

	if (i_arg) {
		outargname_sz = (long)(strlen(i_arg) + 1);
		outargname = kzalloc(outargname_sz, PAF_KERNEL);
		if (!outargname) {
			ret = -ENOMEM;
			goto out;
		}
		strcpy(outargname, i_arg);
	}
	
	info->ae_info.script_name = outappname;
	info->ae_info.script_name_sz = outappname_sz;
	info->ae_info.script_arg = outargname;
	info->ae_info.script_arg_sz = outargname_sz;
	
	if (buf)
		kfree(buf);
	return 0;

out:
	if (buf)
		kfree(buf);
	if(outappname)
		kfree(outappname);
	if(outargname)
		kfree(outappname);
	return ret;
}

static int vmem_file_preparse(struct exec_info* info, const char* filename, char * const *argv,
				char * const *envp)
{
	int scriptfd = -1;
 	int fd = -1;
	int ret;
	char* result = NULL;

	ret = clone_user_string(filename, &result);
	if (IS_ERR(result))
		return PTR_ERR(result);
	
	fd = sys_open(filename, O_RDWR, 0);
	if (fd < 0) {
		discard_user_string(result);
		return -EBADF;
	}

	ret = script_file_preparse(info, fd);
	if (ret) {
		sys_close(fd);
		discard_user_string(result);
		return ret;
	}
	
	if (info->ae_info.script_name) {
		scriptfd = sys_open(info->ae_info.script_name, O_RDWR, 0);
		if (scriptfd < 0) {
			sys_close(fd);
			discard_user_string(result);
			return -EBADF;
		}
		if (elf_file_preparse(info, scriptfd)) {
			if (scriptfd >= 0) 
				sys_close(scriptfd);
			if (fd >= 0)
				sys_close(fd);
			discard_user_string(result);
			return -EFAULT;
		}
	} else {
		if (elf_file_preparse(info, fd)) {
			if (scriptfd >= 0) 
				sys_close(scriptfd);
			if (fd >= 0)
				sys_close(fd);
			discard_user_string(result);
			return -EFAULT;
		}
	}

	info->ae_info.app_argv = argv;
	info->ae_info.app_envp = envp;
	info->ae_info.script_fd = scriptfd;
	info->ae_info.fd = fd;
	info->ae_info.filename = result;
	info->ae_info.filename_sz = strlen(info->ae_info.filename) + 1;

	return 0;	
}

static int vmem_file_execve(struct exec_info* info, const char* filename, char * const *argv,
				char * const *envp, int state)
{
	int exefd = -1;
	int scriptfd = -1;
	int ret;

	ret = vmem_file_preparse(info, filename, argv, envp);
	if (ret)
		goto out;

	if (info->ae_info.script_name && info->ae_info.script_fd > 0) {
		exefd = info->ae_info.script_fd;
		memcpy(current->name, info->ae_info.script_name, sizeof(current->name));
		memcpy(current->bin_path, info->ae_info.script_name, sizeof(current->bin_path));
		scriptfd = exefd;
	} else if (info->ae_info.fd > 0 ) {
		memcpy(current->name, info->ae_info.filename, sizeof(current->name));
		memcpy(current->bin_path, info->ae_info.filename, sizeof(current->bin_path));
		exefd = info->ae_info.fd;
	} else {
		BUG();
	}

	ret = task_argenv_kernel(info, argv, envp);
	if (ret) {
		goto out;
	}
	
	if (state == OLD_EXECVE_STATE) {
		/**
		 * 由于调度可能会重新加载地址空间，所以这里要关闭抢占调度
		 */
		preempt_disable();
		/* 拆卸之前的用户虚拟内存空间 */
		if ((ret = destroy_process_memspace(current_proc_info()))) {
			preempt_enable();
			goto out;
		}	
		/* 装载新的用户虚拟内存空间(除代码段与数据段) */
		if ((ret = create_process_memspace(current_proc_info()))) {
			preempt_enable();
			goto out;
		}
		preempt_enable();
	}

	/**
	 * 重新刷新虚拟地址空间硬件相关设置
	 * 因为前面可能已经重新建立新的地址空间
	 */
	flush_current_memspace();

	ret = elf_file_execve(info, exefd, argv, envp);
	if (ret) {
		goto out;
	}

	ret = task_argenv_user(info);
	if (ret) {
		goto out;
	}

	/**
	 * 将exec_info结构地址原子写入当前线程描述符的相关字段中
	 */
	info->user_argenv_sp = (void*)info->ae_info.ustart;
	arch_accurate_xchg((u64)info, &(current->user_exec_info), sizeof(info));

	current->self_exec_id++;

	/**
	 * 安装信号相关的sigret函数
	 */
	ret = task_user_signal();
	return ret;
	
out:
	ret = -EFAULT;
	if (scriptfd >= 0)
		sys_close(scriptfd);
	if (info->elf_hdr)
		elf_free_elfhdr(info->elf_hdr);
	return ret;
}

/**
 * execve核心实现
 */
static int vmem_execve_core(const char *filename, 
					char * const *argv, char * const *envp)
{
	
	struct exec_info* info = NULL;
	int ret;
#ifdef CONFIG_MIPS64
	int fd;
	/**
	 * FIXME: 这里打开null设备替代console，等有串口驱动后替换。
	 */
	fd = sys_open("/dev/null", O_RDWR, 0);
	if (fd < 0)
		return -1;
#else
	if (execve_open_stdio()) {
		return -EIO;
	}
#endif

	info = alloced_exec_info();
	if (!info) {
		ret = - ENOMEM;
		goto out;
	}

	ret = vmem_file_execve(info, filename, argv, envp, NEW_RUNBIN_STATE);
	if (ret) {
		goto out;
	}

	exec_info_clean(info);
	WARN_ON(ret, "vmem_execve_core->excev_argv_env");
	return 0;

out:	
	if (info)
		free_exec_info(info);
#ifdef CONFIG_MIPS64
	sys_close(fd);
#else
	execve_close_stdio();
#endif
	return ret;
}

void set_dumpable(struct mem_desc *mem, int value)
{
	if (WARN_ON((unsigned)value > SUID_DUMP_ROOT))
		return;

	set_mask_bits((long*)(&mem->flags), MMF_DUMPABLE_MASK, value);
}

char *__get_task_name(char *buf, size_t buf_size, struct task_desc *tsk)
{
	task_lock(tsk);
	strncpy(buf, tsk->name, buf_size);
	task_unlock(tsk);
	return buf;
}

void __set_task_name(struct task_desc *tsk, const char *buf, bool exec)
{
	task_lock(tsk);
	strlcpy(tsk->name, buf, sizeof(tsk->name));
	task_unlock(tsk);
}

/**
 * execve接口
 */
int vmem_execve(const char *filename, char * const *argv,
					char * const *envp)
{
	if (!filename)
		return -EINVAL;

	return vmem_execve_core(filename, argv, envp);
}

static int task_execve_core(const char *filename, 
	char * const *argv, char * const *envp, struct exception_spot* regs)
{
	struct exec_info* info;
	unsigned long newsp;
	int ret;
	info = alloced_exec_info();
	if (!info) {
		return -ENOMEM;
	}
	
	
	ret = vmem_file_execve(info, filename, argv, envp, OLD_EXECVE_STATE);
	if (ret) {
		free_exec_info(info);
		return -EFAULT;
	}
	
	exec_info_clean(info);

	/* 5. 修改返回值与堆栈 */
	if (current->fp_regs)
		memset(current->fp_regs, 0x0, sizeof(struct fp_context));
	memset(&current->task_spot, 0x0, sizeof(struct task_spot));
	if (current->user_exec_info && current->user_exec_info->user_argenv_sp) {
		/**
		 * 有命令行参数和环境变量的情况
		 */
		newsp = (u64)(current->user_exec_info->user_argenv_sp);
	} else {
		/**
		 * 没有有命令行参数和环境变量或者处理参数失败的情况
		 */
		newsp = (u64)(mem_stack_top(current_mem) & PAGE_MASK);
	}
	

	current->user_regs = (struct exception_spot*)((u64)current->stack + THREAD_START_SP - S_FRAME_SIZE);
	
	
	arch_set_execve_regs(regs, (u64)current->task_main, newsp);
	

	return 0;
}

int task_execve(const char *filename, char * const *argv, 
						char * const *envp, 
						struct exception_spot* regs)
{
	return task_execve_core(filename, argv, envp, regs);
}


int exit_execv_info(struct task_desc* t)
{
	if (!t)
		return -EINVAL;
	if(!t->user_exec_info)
		return 0;
	
	free_exec_info(t->user_exec_info);

	arch_accurate_xchg((u64)NULL, &(t->user_exec_info), sizeof(t->user_exec_info));
	return 0;
}
